﻿using ProjScan.Config;
using ProjScan.RecordManager;
using ProjScan.ScanGUI;
using ProjScan.ScanRule;
using ProjScan.ScanRule.Attr;
using ProjScan.Submodules.Effects_Play_Check;
using ProjScan.Tools;
using System;
using System.IO;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;

namespace ProjScan.Modules
{
    [InitializeOnLoad]
    internal class EffectsPlayCheckModule : BaseModules<EffectsPlayCheckModule, EffectsPlayCheckConfig>
    {
        private int resolutionWidth = 720;

        private int resolutionHeight = 720;

        static EffectsPlayCheckModule()
        {
            EditorApplication.update = (EditorApplication.CallbackFunction)Delegate.Combine(EditorApplication.update, new EditorApplication.CallbackFunction(Singleton<EffectsPlayCheckModule>.Instance.ProcessModuleUpdate));
        }

        private void ProcessModuleUpdate()
        {
            if (ProjectSpecificEditorPrefs.HasKey("PerformanceEnhancementProfileRun") && EditorApplication.isPlaying && EditorApplication.isPlayingOrWillChangePlaymode)
            {
                ProjectSpecificEditorPrefs.DeleteKey("PerformanceEnhancementProfileRun");
                HandleEditorPlayMode();
            }
        }

        private void HandleEditorPlayMode()
        {
            Singleton<PerformanceMeasurer>.Instance.Init();
            Singleton<PerformanceMeasurer>.Instance.PushState("Effect_Play_Check");
            ToolsHelper.ShowProgressBar("Effect Play Check", "Preparing...", 0.01f);
            Init();
            LoadRules(LoadMode.Check);
            if (baseRules_Check == null || baseRules_Check.Count == 0)
            {
                ScanLog.Instance.LogInfo(Module.Effects_Play_Check, ScanLog.Stage.s2, "Rules is empty");
                ScanLog.UnityLogError("特效检测运行失败：相关规则全部关闭");
                Close();
                return;
            }

            InitRules(5000);
            RecordManagerFactory.Instance.RecordRuleInit(recordRules_Check);
            try
            {
                ScanLog.UnityLog("正在准备粒子特效数据。");
                RecordManagerFactory.Instance.PrepareAssets();
            }
            catch (Exception ex)
            {
                ScanLog.Instance.LogInfo(ScanLog.LogLevel.EXCEPTION, Module.Effects_Play_Check, ScanLog.Stage.s2, "Output", ((ex.GetType() == null) ? null : ex.GetType().ToString()) + "\n" + ex.Message + "\n" + ex.StackTrace);
                if (ex.Message == "Managers is empty")
                {
                    ScanLog.UnityLogError("特效检测：请检查特效检测相关规则是否全部关闭。");
                }

                Close();
            }
        }

        public override void Run(StreamWriter streamWriter)
        {
            if (Application.isPlaying)
            {
                EditorUtility.DisplayDialog("Proj Scan tips", "Please exit the Play mode before scanning.", "OK");
                return;
            }

            if (ApiCompatibilityUtils.Instance.HasCompileError())
            {
                ScanLog.UnityLogError("存在编译错误，无法进入Play Mode，跳过特效检测");
                ToolsHelper.ClearProgressBar();
                Init();
                LoadRules(LoadMode.Check);
                AllRuleFailed();
                Singleton<ScanOverviewManager>.Instance.SetModulesRunError("Effects_Play_Check");
                Finish();
                return;
            }

            ScanLog.Instance.LogInfo(Module.Effects_Play_Check);
            ToolsHelper.ShowProgressBar("Effect Profiler", "Preparing...", 0.01f);
            Debug.Log("Proj Scan: 粒子特效分析功能开始运行。");
            GameViewSizeManager.SetResolution(resolutionWidth, resolutionHeight, "Proj ScanScreen");
            EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects);
            bool result = false;
            AssemblyTools.I.TryGetMethodResult("UnityEditor.ConsoleWindow", "GetConsoleErrorPause", out result, null);
            ProjectSpecificPlayerPrefs.SetInt("PreviousErrorPause", result ? 1 : 0);
            object[] parameters = new object[1]
            {
                false
            };
            AssemblyTools.I.TryInvokeUnityEditorMethod("UnityEditor.ConsoleWindow", "SetConsoleErrorPause", parameters);
            Camera main = Camera.main;
            main.clearFlags = CameraClearFlags.Color;
            main.backgroundColor = Color.black;
            main.orthographic = true;
            AssemblyTools.I.SetPropertyValue(main, "AllowHDR", false);
            AssemblyTools.I.SetPropertyValue(main, "AllowMSAA", false);
            Camera camera = new GameObject("OverdrawCamera").AddComponent<Camera>();
            camera.clearFlags = CameraClearFlags.Color;
            camera.backgroundColor = Color.black;
            camera.orthographic = true;
            camera.depth = -5f;
            AssemblyTools.I.SetPropertyValue(camera, "AllowHDR", false);
            AssemblyTools.I.SetPropertyValue(camera, "AllowMSAA", false);
            Camera camera2 = new GameObject("BgCamera").AddComponent<Camera>();
            camera2.clearFlags = CameraClearFlags.Color;
            camera2.backgroundColor = Color.black;
            camera2.cullingMask = 0;
            camera2.depth = -10f;
            AssemblyTools.I.SetPropertyValue(camera2, "AllowHDR", false);
            AssemblyTools.I.SetPropertyValue(camera2, "AllowMSAA", false);
            ProjectSpecificEditorPrefs.SetBool("PerformanceEnhancementProfileRun", value: true);
            EditorApplication.isPaused = false;
            EditorApplication.isPlaying = true;
        }

        private void AllRuleFailed()
        {
            for (int i = 0; i < recordRules_Check.Count; i++)
            {
                RecordRule recordRule = recordRules_Check[i];
                recordRule.CreateNewOutputDetailFile();
            }
        }

        public override void Init()
        {
            ScanLog.Instance.OpenScanLog(ReceiveUnityLog: false);
            Singleton<ModulesManager>.Instance.Init();
            rulesSw = Singleton<FileStreamFactory>.Instance.GetStreamWriter(ToolsHelper.GetScanOutPut() + "/rules.csv", append: true);
            thresSw = Singleton<FileStreamFactory>.Instance.GetStreamWriter(ToolsHelper.GetScanOutPut() + "/thres.csv", append: true);
            AssetPathManager.Instance.FindAssetPath(isCheckDir: true);
            config = (Singleton<ConfigMgr>.Instance.GetConfig<EffectsPlayCheckConfig>() as EffectsPlayCheckConfig);
            baseRules_Check.Clear();
            recordRules_Check.Clear();
            globalRules_Check.Clear();
            ruleAttr = typeof(ParticleEffctRuleAttr);
            RecordManagerFactory.Instance.Init();
        }

        public override void Close()
        {
            ScanLog.UnityLog("特效检测模块阶段结束");
            for (int i = 0; i < recordRules_Check.Count; i++)
            {
                RecordRule recordRule = recordRules_Check[i];
                ToolsHelper.ShowProgressBar("Output data", $"Scan:{recordRule.GetType().Name}({i + 1}/{recordRules_Check.Count})", 0.5f * (float)(i + 1) / (float)recordRules_Check.Count);
                recordRule.OutputData();
                recordRule.OutputDetailData();
                recordRule.DumpToRuleCSV(ref rulesSw);
                recordRule.DumpToThresCSV(ref thresSw);
            }

            RecordManagerFactory.Instance.OutPutScanScr();
            ScanLog.Instance.LogInfo(Module.Basic_Assets_Check, ScanLog.Stage.s5, "Done.");
            RecordManagerFactory.Instance.Close();
            bool flag = ProjectSpecificPlayerPrefs.GetInt("previousErrorPause") == 1;
            object[] parameters = new object[1]
            {
                flag
            };
            AssemblyTools.I.TryInvokeUnityEditorMethod("UnityEditor.ConsoleWindow", "SetConsoleErrorPause", parameters);
            EditorApplication.isPlaying = false;
            ScanLog.Instance.LogInfo(Module.Effects_Play_Check, ScanLog.Stage.s6, "Done.");
            Singleton<PerformanceMeasurer>.Instance.CloseAndRecordState();
            Finish();
        }

        private void Finish()
        {
            Singleton<ModulesManager>.Instance.Close();
            Singleton<ModulesManager>.Instance.InitFailedResultManager();
            Singleton<ModulesManager>.Instance.OutputScanOverResult();
            if (!Singleton<ScanInfo>.Instance.isScanQuit)
            {
                EditorApplication.delayCall = (EditorApplication.CallbackFunction)Delegate.Combine(EditorApplication.delayCall, new EditorApplication.CallbackFunction(DelayStop));
            }

            Singleton<ModulesManager>.Instance.CheckQuit();
        }

        private static void DelayStop()
        {
            EditorApplication.delayCall = (EditorApplication.CallbackFunction)Delegate.Remove(EditorApplication.delayCall, new EditorApplication.CallbackFunction(DelayStop));
            EditorApplication.isPlaying = false;
            Singleton<ModulesManager>.Instance.OpenScanOverviewWindow();
        }
    }
}